package edu.utd.text.game.controller;

import edu.utd.text.game.controller.commands.GameCommand;
import edu.utd.text.game.domain.GameMap;
import edu.utd.text.game.domain.areas.Room;
import edu.utd.text.game.domain.player.Player;
import edu.utd.text.game.tests.mocks.FakeAxe;
import edu.utd.text.game.tests.mocks.FakeKnife;
import edu.utd.text.game.tests.mocks.FakeShovel;

public class Controller {
	private GameMap gameMap;
	private Player player;
	
	public final static Controller INSTANCE = new Controller(); 
	
	private Controller() {
		initialize();
	}
	
	public void initialize() {
		//loadTestGame();
		
		//TODO: Come up some default loading behavior, 
		//maybe start by trying to load some default save file.
		
		this.player = new Player();
		
		if (null == gameMap) gameMap = new GameMap();
		Room startingRoom = new Room("Starting Room.");
		startingRoom.setDescription("You have to load a game before you can do anything.");
		player.setCurrentRoom(startingRoom);
		
		//TODO: hack job, refactor soon
		if (gameMap.getMainRoom() != null) {
			player.setCurrentRoom(gameMap.getMainRoom());
		}
	}
	
	public void loadTestGame() {
		//in real life we may load serialized objects
		//for now, for testing purposes, we will simply create some objects here
		Room livingRoom = new Room("Living Room");
		Room diningRoom = new Room("Dining Room");
		Room kitchen = new Room("Kitchen");
		
		//create descriptions for rooms
		livingRoom.setDescription(
				"This is the LIVING ROOM.  There is some really nice stuff in here.\n" +
				"There is an exit to the WEST.");
		diningRoom.setDescription(
				"This is the DINING ROOM.  There is a table with seven chairs around it.\n" +
				"Exits are to the NORTH and the EAST.");
		kitchen.setDescription(
				"This is the KITCHEN.  There is a stove and some pots and pans in here.\n" +
				"There is one exit to the SOUTH.");
		
		//connect the rooms
		livingRoom.setWestExit(diningRoom);
		diningRoom.setEastExit(livingRoom);
		diningRoom.setNorthExit(kitchen);
		kitchen.setSouthExit(diningRoom);
		
		//put objects in the rooms
		try { livingRoom.addGameObject(new FakeAxe()); } catch (Exception x) { ; }
		try { livingRoom.addGameObject(new FakeShovel()); } catch (Exception x) { ; }
		try { diningRoom.addGameObject(new FakeAxe()); } catch (Exception x) { ; }
		try { kitchen.addGameObject(new FakeKnife()); } catch (Exception x) { ; }
		
		
		
		
		//the room where the player beings the game
		this.player = new Player();
		this.player.setCurrentRoom(livingRoom);
		
	}
	
	
	
	  //////////////////
	 // Game Actions //
	//////////////////
	
	public String doCommand(GameCommand aCommand) {
		
		try {
			return aCommand.execute();
		} catch (Exception e) {
			return "I don't know how to do that...";
		}
		
		/////////////////////////////////////////////////////////
		// USE THE COMMAND PATTERN FOR THIS KIND OF DELEGATION //
		/////////////////////////////////////////////////////////
//		if (aCommand instanceof BooleanCommand) {
//			return "Yeah, whatever.";
//		} 
//		else if (aCommand instanceof MovementCommand) {
//			return doMove((MovementCommand)aCommand);
//		} 
//		else if (aCommand instanceof ExamineCommand) {
//			return doExamine((ExamineCommand)aCommand);
//		}
//		else if (aCommand instanceof PickupCommand) {
//			return doPickup((PickupCommand)aCommand);
//		}
//		else if (aCommand instanceof DropItemCommand) {
//			return doDropItem((DropItemCommand)aCommand);
//		}
//		else if (aCommand instanceof ShowInventoryCommand) {
//			return doShowInventory((ShowInventoryCommand)aCommand);
//		}
//		else return "I'm not familiar with that terminology.";
		
		
	}
	
//	public String doMove(MovementCommand aMove) {
//		try {
//			getPlayer().moveDirection(aMove.getDirectionToMove());
//		} catch (DeadEndEncounteredException deex) {
//			return "That way is a dead end.";
//		} catch (InvalidDirectionException idx) {
//			return "Can't go that way.";
//		} 
//		return getPlayer().getCurrentRoom().getDescription();
//	}
//	
//	//TODO : Test the tagging mechanism for game objects
//	public String doExamine(ExamineCommand anExam) {
//		
//		//if there is an object (target) assoc w/ this exam command, try to find it in the room
//		if (null != anExam.getObjectToExamine() && !anExam.getObjectToExamine().isEmpty()) {
//				String objectToExam = anExam.getObjectToExamine();
//				
//				ArrayList<GameObject> objectsInRoom = getPlayer().getCurrentRoom().getObjects();
//				
//				for (GameObject gameObject : objectsInRoom) {
//					if (gameObject.getTags().contains(objectToExam)) {
//						return gameObject.getDescription();
//					}
//				}
//				return "I don't see a \"" + objectToExam + "\" here...";
//		} else {
//			//if there was no object (target) of the exam command, exam the room
//			return getPlayer().getCurrentRoom().getDescription(); 
//		}
//	}
//	
//	public String doPickup(PickupCommand pickupCommand) {
//		String objectToPickup = pickupCommand.getObjectToPickup();
//		ArrayList<GameObject> objectsInRoom = getPlayer().getCurrentRoom().getObjects();
//		
//		for (GameObject gameObject : objectsInRoom) {
//			if(gameObject.tagsMatch(objectToPickup)) {
//				if(gameObject instanceof GameItem) {
//					try {
//						getPlayer().pickupItem((GameItem)gameObject);
//						return "Got " + gameObject.getName() + ".";
//					} catch (ItemAlreadyExistsInInventoryException iaeiix) {
//						return "You are already carrying one of those!";
//					} catch (MaxItemsExceededException miex) {
//						return "You can't hold any more items in your inventory.  Drop something first.";
//					} catch (GameObjectNotFoundException gonfx) {
//						handleException(gonfx);
//					}
//				} 
//				else {
//					return "You can't carry that!";
//				}
//			}
//		}
//		return "I don't see one of those here...";
//	}
//	
//	public String doDropItem(DropItemCommand dropItemCmd) {
//		String itemToDrop = dropItemCmd.getItemToDrop();
//		if (getPlayer().hasItem(itemToDrop)) {
//			if(getPlayer().dropItemInRoom(itemToDrop)) {
//				return "Dropped " + itemToDrop + ".";
//			}
//			else {
//				return "Cannot drop that here.";
//			}
//		}
//		return "You are not carrying one of those!";
//	}
//	
//	public String doShowInventory(ShowInventoryCommand showInventoryCmd) {
//		ArrayList<String> itemsInInventory = getPlayer().getInventory().listInventory();
//		if(itemsInInventory.isEmpty()) {
//			return "You are not carrying any items.";
//		}
//		String list = "You are carrying the following items:";
//		for (String itemName : itemsInInventory) {
//			list += "\n" + itemName;
//		}
//		return list;
//	}
	

	
	  /////////////////////
	 // Utility methods //
	/////////////////////
	
	//
	//Nothing here now
	//
	
	
	  ////////////////////////
	 // Exception Handling //
	////////////////////////
	
	public void handleException(Exception e) {
		//Later this will do something a little more graceful
		//but for now just dump the error to the console so
		//we can see it
		e.printStackTrace();
	}
	
	
	  /////////////
	 // Getters //
	/////////////
	
	public GameMap getGameMap() {
		return gameMap;
	}
	
	public Player getPlayer() {
		return player;
	}
	
	
	  /////////////
	 // Setters //
	/////////////
	
	public void setGameMap(GameMap map) {
		gameMap = map;
	}
	
	public void setPlayer(Player player) {
		this.player = player;
	}
}
